
/**
\file
Defines the rainbow::decorated_draw_information struct.
\author Sean Tromans
*/

#include <sun_pre_compiled.hpp>
#include <rainbow/viewport/pass/decorated_draw_information/decorated_draw_information.hpp>

#if !defined(SUN_DISABLE_LUA)
#include <sun/lua/lua.hpp>
#endif

namespace rainbow
{
	//
	//	Public Member Functions
	//

	/**
	Default Constructor.
	\author Sean Tromans
	*/
	decorated_draw_information::decorated_draw_information( )
		:		depth( -1.0f )
			,	info( )
	{
	}

	/**
	Constructor.
	@param depth The approximate depth of the mesh to be drawn.
	@param info The information explaining how to draw the provided mesh.
	\author Sean Tromans
	*/
	decorated_draw_information::decorated_draw_information( float depth, draw_information const & info )
		:		depth( depth )
			,	info( info )
	{
	}

	//
	//	Static Member Functions
	//

	/**
	Exposes the draw_command to lua.
	@param L The Lua State being initialised.
	\author Sean Tromans.
	*/
	void decorated_draw_information::lua_interface( lua_State * L )
	{
#if !defined(SUN_DISABLE_LUA)
		luabind::module( L, "rainbow" )
		[
			luabind::class_< decorated_draw_information >( "decorated_draw_information" )
				.def( luabind::constructor<float, draw_information const &>( ) )
				.def_readwrite( "depth", &decorated_draw_information::depth )
				.def_readwrite( "info", &decorated_draw_information::info )

				.scope
				[
					luabind::def( "default_ordering",			decorated_draw_information::default_ordering ),
					luabind::def( "order_without_transparency",	decorated_draw_information::order_without_transparency )
				]
		];
#else
		NMN_UNUSED( L );
#endif
	}

	/**
	The default ordering of decorated_draw_informations.
	Orders opaque objects ahead of transparent objects.
	If opaque sorts by material then from front to back.
	If transparent sorts from back to front, then by material.
	@param a The first decorated_draw_information to compare.
	@param b The first decorated_draw_information to compare.
	@returns true if a compares less than b. False otherwise.
	\author Sean Tromans
	*/
	bool decorated_draw_information::default_ordering( decorated_draw_information const & a, decorated_draw_information const & b )
	{
		blend_state const & blend_a = a.info.device->get_blend_state( a.info.blend_handle );
		blend_state const & blend_b = b.info.device->get_blend_state( b.info.blend_handle );

		if ( blend_a.enabled == blend_b.enabled )
		{
			if ( blend_a.enabled )
			{
				return a.depth > b.depth;
			}
			else
			{
				return order_without_transparency( a, b );
			}
		}
		else
		{
			if ( blend_a.enabled )
			{
				return false;
			}
			else
			{
				return true;
			}
		}
	}

	/**
	Similar to the default ordering mechanism, but ignored the opacity setting of the information.
	First sorts by material and then sorts from front-to-back.
	@param a The first decorated_draw_information to compare.
	@param b The first decorated_draw_information to compare.
	@returns true if a compares less than b. False otherwise.
	\author Sean Tromans
	*/
	bool decorated_draw_information::order_without_transparency( decorated_draw_information const & a, decorated_draw_information const & b )
	{
		return draw_information::materials_equal( a.info, b.info ) ? a.depth < b.depth : draw_information::default_ordering( a.info, b.info );
	}
};
